<?php

/*
Copyright 2009-2011 Sam Weiss
All Rights Reserved.

This file is part of Spark/Plug.

Spark/Plug is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

if (!defined('spark/plug'))
{
	header('HTTP/1.1 403 Forbidden');
	exit('<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"><html><head><title>403 Forbidden</title></head><body><h1>Forbidden</h1><p>You don\'t have permission to access the requested resource on this server.</p></body></html>');
}

// -----------------------------------------------------------------------------

class SparkLangPlug extends SparkPlug
{
	public static $lang = NULL;
	
	public function __construct()
	{
		parent::__construct();
		self::$lang || self::$lang = new SparkLang($this->app, NULL, NULL);
	}
}

// -----------------------------------------------------------------------------

final class SparkLang
{
	private $_language;
	private $_langFileExt;
	private $_langDirStack;
	private $_observer;
	private $_loaded;
	private $_text;
	private $_loadDepth;	// recursion depth in load
	private $_loading;	// current lang file being loaded

// -----------------------------------------------------------------------------

	public function __construct($app, $language = NULL, $langDir = NULL)
	{

		$config = $app->config();
		
		$this->_language = empty($language) ? $config->get('language', 'en_US') : $language;
		$this->_langFileExt = $config->get('language_name_extension', '');

		$this->pushLangDir($app->spDir() . '/languages');
		$this->pushLangDir($config->get('lang_dir', $app->appDir() . '/languages'));

		$this->_observer = $app->observer;
		$this->_loaded = array();
		$this->_text = array();
		$this->_loadDepth = 0;
		$this->_loading = false;
		
		if (!empty($this->_langFileExt))
		{
			$this->_langFileExt = '_' . $this->_langFileExt;
		}
	}

// -----------------------------------------------------------------------------

	final public function pushLangDir($dir)
	{
		$this->_langDirStack[] = $dir;
	}
	
// -----------------------------------------------------------------------------

	final public function popLangDir()
	{
		if (count($this->_langDirStack) > 1)
		{
			return array_pop($this->_langDirStack);
		}
		return $this->_langDirStack[0];
	}
	
// -----------------------------------------------------------------------------

	final public function load($file, $dir = NULL, $language = NULL, $return = false, $merge = true)
	{
		// is the language file already loaded?
		
		if (!empty($this->_loaded[$file]) && !$this->_loading)
		{
			return $return ? $this->_loaded[$file] : true;
		}
		
		// if this is a recursive call, disallow loading of a language dictionary other
		// than the one that initiated this load
		
		if ($this->_loadDepth && ($file !== $this->_loading))
		{
			return false;
		}
		
		$langFileNameBase = SparkInflector::decamelize($file);
		$langFileName = $langFileNameBase . $this->_langFileExt;

		if (empty($language))
		{
			$language = $this->_language;
		}

		if (!empty($dir))
		{
			include("{$dir}/{$language}/{$langFileName}.php");
		}

		if (empty($lang))
		{
			for ($iLangDir = count($this->_langDirStack) - 1; $iLangDir > 0; --$iLangDir)
			{
				if (file_exists($langPath = "{$this->_langDirStack[$iLangDir]}/{$language}/{$langFileName}.php"))
				{
					include($langPath);
					break;
				}
			}
		}
		
		if (empty($lang))
		{
			if (file_exists($langPath = "{$this->_langDirStack[$iLangDir]}/{$language}/{$langFileNameBase}.php"))
			{
				include($langPath);
			}
		}
		
		if (empty($lang))
		{
			return false;
		}
		
		foreach ($lang as $dict)
		{
			$this->_loaded[$file] = empty($this->_loaded[$file]) ? $dict : array_merge($this->_loaded[$file], $dict);
		}
		
		// give plugins a chance to load their language additions

		if (++$this->_loadDepth === 1)
		{
			$this->_loading = $file;
			$this->_observer->notify('SparkLang:load:'.$file, $file);
		}
		
		if (--$this->_loadDepth === 0)
		{
			$this->_loading = false;
			if ($merge)
			{
				$this->_text = array_merge($this->_text, $this->_loaded[$file]);
			}
		}

		return $return ? $this->_loaded[$file] : true;
	}

// -----------------------------------------------------------------------------

	final public function get($key)
	{
		if ($text = @$this->_text[$key])
		{
			if ($c = func_num_args() - 1)
			{
				$vars = func_get_args();
				array_shift($vars);
				$text = self::replaceText($text, $vars);
			}
			return $text;
		}
		return ucwords(SparkInflector::humanize($key));
	}

// -----------------------------------------------------------------------------

	final public static function replaceText($text, $vars)
	{
		switch ($c = count($vars))
		{
			case 0:
				break;
			case 1:
				$text = sprintf($text, $vars[0]);
				break;
			case 2:
				$text = sprintf($text, $vars[0], $vars[1]);
				break;
			case 3:
				$text = sprintf($text, $vars[0], $vars[1], $vars[2]);
				break;
			case 4:
				$text = sprintf($text, $vars[0], $vars[1], $vars[2], $vars[3]);
				break;
			case 5:
				$text = sprintf($text, $vars[0], $vars[1], $vars[2], $vars[3], $vars[4]);
				break;
			default:
				for ($i = 1; $i <= $c; ++$i)
				{
					$search[] = "%{$i}\$s";
				}
				$text = str_replace($search, $vars, $text);
		}
		
		return $text;
	}
	
// -----------------------------------------------------------------------------

}
